﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Core.Infrastructure.ScreenManager;
using TypeMock.ArrangeActAssert;
using System.Windows.Controls;
using CThru.Silverlight;
using ThemeLoader;
using Core.Infrastructure.EventArgs;

namespace Core.Infrastructure.Test
{
    [TestFixture]
    public class ScreenBaseTest
    {
        private ScreenBase screenBase;
        private IResourceProvider resourceProvider;

        [SetUp, SilverlightSetUp]
        public void Setup()
        {
            resourceProvider = Isolate.Fake.Instance<IResourceProvider>();
            screenBase = Isolate.Fake.Instance<ScreenBase>();
            screenBase.ResourceProvider = resourceProvider;
        }

        [Test, SilverlightUnitTest]
        [ExpectedException(typeof(InvalidOperationException))]
        public void RecreateView_RegisterViewNotCalled_ThrowInvalidOperationException()
        {
            Isolate.WhenCalled(() => screenBase.RecreateView()).CallOriginal();

            screenBase.RecreateView();
        }

        [Test, SilverlightUnitTest]
        public void RecreateView_RegisterViewCalled_UpdateCouplingCalled()
        {
            Isolate.WhenCalled(() => screenBase.RecreateView()).CallOriginal();
            Isolate.WhenCalled(() => screenBase.RegisterView<ContentControl>()).CallOriginal();
            screenBase.RegisterView<ContentControl>();

            screenBase.RecreateView();

            Isolate.Verify.WasCalledWithAnyArguments(() => screenBase.UpdateCoupling());
        }

        [Test, SilverlightUnitTest]
        public void RecreateView_RegisterViewCalledStyleKeyIsNullOrEmpty_GetResourceIsNotCalled()
        {
            Isolate.WhenCalled(() => screenBase.RecreateView()).CallOriginal();
            Isolate.WhenCalled(() => screenBase.RegisterView<ContentControl>()).CallOriginal();
            screenBase.RegisterView<ContentControl>();
            screenBase.StyleKey = "";

            screenBase.RecreateView();

            Isolate.Verify.WasNotCalled(() => this.resourceProvider.GetResource("anyKey"));
        }

        [Test, SilverlightUnitTest]
        public void RecreateView_RegisterViewCalledStyleKeyNotNull_GetResourceIsCalled()
        {
            Isolate.WhenCalled(() => screenBase.RecreateView()).CallOriginal();
            Isolate.WhenCalled(() => screenBase.RegisterView<ContentControl>()).CallOriginal();
            screenBase.RegisterView<ContentControl>();
            screenBase.StyleKey = "styleKey";

            screenBase.RecreateView();

            Isolate.Verify.WasCalledWithExactArguments(() => this.resourceProvider.GetResource("styleKey"));
        }

        [Test, SilverlightUnitTest]
        [ExpectedException(typeof(InvalidOperationException))]
        public void GetView_RegisterViewNotCalled_ThrowInvalidOperationException()
        {
            Isolate.WhenCalled(() => screenBase.RecreateView()).CallOriginal();
            Isolate.WhenCalled(() => screenBase.View).CallOriginal();

            var view = screenBase.View;
        }

        [Test, SilverlightUnitTest]
        public void GetView_ViewNotCreated_RecreateViewIsCalled()
        {
            Isolate.WhenCalled(() => screenBase.RecreateView()).IgnoreCall();
            Isolate.WhenCalled(() => screenBase.View).CallOriginal();

            var view = screenBase.View;

            Isolate.Verify.WasCalledWithAnyArguments(() => screenBase.RecreateView());
        }

        [Test, SilverlightUnitTest]
        public void DataContextSet_RegisterViewCalled_UpdateCouplingCalled()
        {
            Isolate.WhenCalled(() => screenBase.RecreateView()).CallOriginal();
            Isolate.WhenCalled(() => screenBase.RegisterView<ContentControl>()).CallOriginal();
            screenBase.RegisterView<ContentControl>();

            screenBase.RecreateView();

            Isolate.Verify.WasCalledWithAnyArguments(() => screenBase.UpdateCoupling());
        }

        [Test, SilverlightUnitTest]
        public void Activate_ViewModelNull_ExcpetionNotThrown()
        {
            var args = new ScreenEventArgs();

            Assert.DoesNotThrow(() => screenBase.Activate(args));
        }

        [Test, SilverlightUnitTest]
        public void Activate_ViewModeltNotNavigable_ExcpetionNotThrown()
        {
            var args = new ScreenEventArgs();
            screenBase.ViewModel = new object();

            Assert.DoesNotThrow(() => screenBase.Activate(args));
        }

        [Test, SilverlightUnitTest]
        public void Activate_ViewModelIsGenericNavigable_NavigateCalled()
        {
            var navigable = Isolate.Fake.Instance<INavigable<string>>();
            screenBase.ViewModel = navigable;
            Isolate.WhenCalled(() => screenBase.Activate(null)).CallOriginal();
            var args = new ScreenEventArgs()
            {
               NavigationArgs = "navigationArgs" 
            };       

            screenBase.Activate(args);

            Isolate.Verify.WasCalledWithExactArguments(() => navigable.OnNavigate("navigationArgs"));
        }

        [Test, SilverlightUnitTest]
        public void Activate_ViewModelIsNavigableNullArgs_NavigateCalled()
        {
            var navigable = Isolate.Fake.Instance<INavigable>();
            screenBase.ViewModel = navigable;
            var args = new ScreenEventArgs()
            {
                NavigationArgs = null,
            };

            screenBase.Activate(args);

            Isolate.Verify.WasCalledWithExactArguments(() => navigable.OnNavigate());
        }

        [Test, SilverlightUnitTest]
        public void Activate_ViewModelIsGenericNavigableOfMultipleTypes_ProperNavigateCalled()
        {
            var navigable = Isolate.Fake.Instance<MultipleNavigator>();
            screenBase.ViewModel = navigable;
            var args = new ScreenEventArgs()
            {
                NavigationArgs = 2,
            };

            screenBase.Activate(args);

            Isolate.Verify.WasCalledWithExactArguments(() => navigable.OnNavigate(2));
        }

        [Test, SilverlightUnitTest]
        [ExpectedException(typeof(ArgumentException))]
        public void Activate_ArgsAreTypeThatIsntPresentNavigalbeInterfaces_ThrowArgumentException()
        {
            var navigable = Isolate.Fake.Instance<MultipleNavigator>();
            screenBase.ViewModel = navigable;
            var args = new ScreenEventArgs()
            {
                NavigationArgs = new DateTime(),
            };

            screenBase.Activate(args);
        }

        public interface MultipleNavigator : INavigable<string>, INavigable<int>, INavigable<double>
        {

        }
    }
}
